﻿using System;
using System.Windows.Markup;
using System.Collections.Generic;
using System.Linq;

using mpu = Microsoft.Practices.Unity;
using mpuu = Microsoft.Practices.Unity.Utility;

using UnityConfiguration.Infrastructure;
using System.Collections.ObjectModel;

namespace UnityConfiguration
{
    [ContentProperty("Items")]
    public class UnityType : TypeResolvingObject, IContainerConfigurationCommand
    {
        private string _TypeName;
        private string _Name;
        private string _MapToName;
        private List<ITypeItem> _Items;

        /// <summary>
        /// The type or alias for the extension to add to the container.
        /// </summary>
        public string TypeName {
            get { return _TypeName; }
            set { _TypeName = value; }
        }

        /// <summary>
        /// Name to use when registering this type. 
        /// </summary>
        public string Name {
            get { return _Name; }
            set { _Name = value; }
        }

        /// <summary>
        /// Destination type for type mapping.
        /// </summary>
        public string MapToName {
            get { return _MapToName; }
            set { _MapToName = value; }
        }

        /// <summary>
        /// The actual <see cref="System.Type"/> object for the 
        /// type this element is registering.
        /// </summary>
        public Type Type {
            get {
                return this.TypeResolver.ResolveType(this.TypeName);
            }
        }

        /// <summary>
        /// The actual <see cref='Type'/> object for the mapTo element in
        /// the configuration file.
        /// </summary>
        public Type MapTo {
            get {
                if (string.IsNullOrEmpty(MapToName)) return null;
                return this.TypeResolver.ResolveType(this.MapToName);
            }
        }

        public List<ITypeItem> Items {
            get { return _Items; }
            set { _Items = value; }
        }

        public Lifetime Lifetime {
            get {
                Lifetime lifetime = this.Items.OfType<Lifetime>().SingleOrDefault();
                if (null != lifetime)
                    lifetime.TypeResolver = this.TypeResolver;
                return lifetime;
            }
        }

        public List<TypeConfiguration> TypeConfigurations {
            get {
                List<TypeConfiguration> typeConfigs = this.Items.OfType<TypeConfiguration>().ToList();
                if (null != typeConfigs)
                    typeConfigs.ForEach(c => c.TypeResolver = this.TypeResolver);
                return typeConfigs;
            }
        }

        public UnityType() {
            this.Items = new List<ITypeItem>();
        }

        /// <summary>
        /// Execute this command against the given container.
        /// </summary>
        /// <remarks>
        /// Interface implementors will implement this method to
        /// apply configuration changes to the container.</remarks>
        /// <param name="container">The <see cref="IUnityContainer"/> to configure.</param>
        public void Configure(mpu.IUnityContainer container) {
            mpuu.Guard.ArgumentNotNull(container, "container");
            mpu.LifetimeManager lifetimeManager = null;
            if (this.Lifetime != null) {
                lifetimeManager = this.Lifetime.CreateLifetimeManager();
            }

            var serviceType = this.Type;
            var implementationType = this.MapTo;

            if (MapTo == null) {
                implementationType = this.Type;
                serviceType = null;
            }

            container.RegisterType(serviceType, implementationType, Name, lifetimeManager);

            foreach (TypeConfiguration typeConfig in this.TypeConfigurations) {
                typeConfig.Parent = this;
                typeConfig.Configure(container);
            }
        }
    }

}
